package br.ufla.pgcc.oomeasures.measures;

import java.util.ArrayList;
import java.util.List;

import org.eclipse.jdt.core.ICompilationUnit;
import org.eclipse.jdt.core.IMethod;
import org.eclipse.jdt.core.IType;
import org.eclipse.jdt.core.ITypeRoot;
import org.eclipse.jdt.core.dom.AST;
import org.eclipse.jdt.core.dom.ASTParser;
import org.eclipse.jdt.core.dom.CompilationUnit;

import br.ufla.pgcc.oomeasures.ASTSession;

public abstract class Measure {
	
	public static enum Granularity {
		PROJECT,
		PACKAGE,
		CLASS,
		METHOD;		
	}
	private List<Granularity> applicableGranularities;
	private static ASTParser parser;
	
	public Measure(){
		applicableGranularities = new ArrayList<Granularity>(4);
		parser = ASTParser.newParser(AST.JLS4);
		parser.setKind(ASTParser.K_COMPILATION_UNIT);
		parser.setResolveBindings(true);
	}
	
	public void addApplicableGranularity(Granularity granularity){
		if (!applicableGranularities.contains(granularity)) {
			applicableGranularities.add(granularity);
		}
	}
	
	public List<Granularity> getAllApplicableGranularities(){
		return applicableGranularities;
	}
	
	public boolean isApplicableGranularity(Granularity granularity){
		return applicableGranularities.contains(granularity);
	}
		
	/** 
	 * Reads a ICompilationUnit and creates the AST DOM for manipulating the 
	 * Java source file 
	 * @param <T>
	 * 
	 * @param unit 
	 * @return 
	 */
	public <T> CompilationUnit parse(T unit) {
		CompilationUnit compilationUnit = null;
		ITypeRoot typeRoot = null;
		
		if (unit instanceof ICompilationUnit) {
			typeRoot = (ITypeRoot)unit;	
		} else if (unit instanceof IMethod) {
			typeRoot = ((IMethod)unit).getTypeRoot();	
		} else if (unit instanceof IType) {
			typeRoot = ((IType)unit).getTypeRoot();
		}
		
		if (!ASTSession.getInstance().contains(typeRoot)) {
			parser.setSource(typeRoot);
			compilationUnit = (CompilationUnit) parser.createAST(null); // parse
			ASTSession.getInstance().save(compilationUnit);
		} else {
			compilationUnit = ASTSession.getInstance().get(typeRoot);
		}
		return compilationUnit;
	}

	public abstract String getName();
	public abstract String getAcronym();
	public abstract String getDescription();
	public abstract double getMinValue();
	public abstract double getMaxValue();
	public abstract double getRefValue();
	public abstract double getCalculatedValue();
	public abstract void setCalculatedValue(double value);
	public abstract <T> void measure(T unit);
	
}
